package citic.c.util;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;

public class Interval implements Comparable<Interval> {
    private BigDecimal start;
    private BigDecimal end;

    public Interval(String start, String end) {
        BigDecimal tStart = new BigDecimal(start);
        BigDecimal tEnd = new BigDecimal(end);
        if (tStart.compareTo(tEnd) > 0) {
            this.start = tEnd;
            this.end = tStart;
        } else {
            this.start = tStart;
            this.end = tEnd;
        }
    }

    public Interval(Integer start, Integer end) {
        BigDecimal tStart = new BigDecimal(start);
        BigDecimal tEnd = new BigDecimal(end);
        if (tStart.compareTo(tEnd) > 0) {
            this.start = tEnd;
            this.end = tStart;
        } else {
            this.start = tStart;
            this.end = tEnd;
        }
    }

    public Interval(Long start, Long end) {
        BigDecimal tStart = new BigDecimal(start);
        BigDecimal tEnd = new BigDecimal(end);
        if (tStart.compareTo(tEnd) > 0) {
            this.start = tEnd;
            this.end = tStart;
        } else {
            this.start = tStart;
            this.end = tEnd;
        }
    }

    public Interval(Double start, Double end) {
        BigDecimal tStart = new BigDecimal(start.toString());
        BigDecimal tEnd = new BigDecimal(end.toString());
        if (tStart.compareTo(tEnd) > 0) {
            this.start = tEnd;
            this.end = tStart;
        } else {
            this.start = tStart;
            this.end = tEnd;
        }
    }

    public Interval(BigDecimal start, BigDecimal end) {
        if (start.compareTo(end) > 0) {
            this.start = end;
            this.end = start;
        } else {
            this.start = start;
            this.end = end;
        }
    }

    public Interval(Date start, Date end) {
        Calendar c = Calendar.getInstance();
        c.setTime(start);
        BigDecimal tStart = new BigDecimal(c.getTimeInMillis());
        c.setTime(end);
        BigDecimal tEnd = new BigDecimal(end.getTime());
        if (tStart.compareTo(tEnd) > 0) {
            this.start = tEnd;
            this.end = tStart;
        } else {
            this.start = tStart;
            this.end = tEnd;
        }
    }


    public Interval swapIn() {
        BigDecimal temp = start;
        start = end;
        end = temp;
        return this;
    }

    public BigDecimal getStart() {
        return start;
    }

    public BigDecimal getEnd() {
        return end;
    }

    public Date getStartToTime() {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(start.longValue());
        return c.getTime();
    }

    public Date getEndToTime() {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(end.longValue());
        return c.getTime();
    }


    public IntervalRelation check(Interval o, BigDecimal step) {
        if (this.equals(o)) {
            return IntervalRelation.same;
        } else {
            if (this.start.compareTo(o.start) < 0) {
                if (this.end.add(step).compareTo(o.start) < 0) {
                    return IntervalRelation.separationLess;
                } else if (this.end.add(step).compareTo(o.start) == 0) {
                    return IntervalRelation.separationLessLink;
                } else if (this.end.add(step).compareTo(o.start) > 0 && this.end.compareTo(o.end) < 0) {
                    return IntervalRelation.intersectLess;
                } else {
                    return IntervalRelation.includeLess;
                }
            } else if (this.start.compareTo(o.start) == 0) {
                if (this.end.compareTo(o.end) < 0) {
                    return IntervalRelation.includeLess;
                } else if (this.end.compareTo(o.end) == 0) {
                    return IntervalRelation.same;
                } else {
                    return IntervalRelation.includeGreat;
                }
            } else if (this.start.compareTo(o.start) > 0 && this.start.compareTo(o.end.add(step)) < 0) {
                if (this.end.compareTo(o.end) <= 0) {
                    return IntervalRelation.includeGreat;
                } else {
                    return IntervalRelation.intersectGreat;
                }
            } else if (this.start.compareTo(o.end.add(step)) == 0) {
                return IntervalRelation.separationGreatLink;
            } else {
                return IntervalRelation.separationGreat;
            }
        }
    }


    public static enum IntervalRelation {
        intersectLess,
        intersectGreat,
        separationLess,
        separationLessLink,
        separationGreat,
        separationGreatLink,
        includeLess,
        includeGreat,
        same,
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Interval interval = (Interval) o;
        return Objects.equals(start, interval.start) &&
                Objects.equals(end, interval.end);
    }

    @Override
    public int hashCode() {

        return Objects.hash(start, end);
    }

    @Override
    public int compareTo(Interval o) {
        if (this.start.compareTo(o.start) > 0) {
            return 1;
        } else if (this.start.compareTo(o.start) < 0) {
            return -1;
        } else {
            if (this.end.compareTo(o.end) > 0) {
                return 1;
            } else if (this.end.compareTo(o.end) < 0) {
                return -1;
            } else {
                return 0;
            }
        }
    }

    @Override
    public String toString() {
        return "Interval{" +
                "start=" + start +
                ", end=" + end +
                '}';
    }
}
